import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Static convenience methods for dealing with zip and gzip files.
 */
public class CompressUtil {
  /**
   * Zip the contents of the provided directories, and save it in the zipfile.
   *
   * @param zipfile  the path/name of the zipfile to create
   * @param basePath the base path in which to find the files to zip. The base
   *                 path will not be included in the zip file entries (and so will not be extracted)
   * @param dirs     the directories (relative to the base path) to add to the zipfile
   * @throws java.io.IOException if the file can't be opened for writing.
   * @throws IllegalArgumentException if one of the File objects in dirs is not a directory
   */
  public static void zipDirectory(File zipfile, File basePath, File... dirs)
      throws IOException, IllegalArgumentException {
    ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile));
    for (File dir : dirs) {
      // Check that the directory is a directory, and get its contents
      if (!new File(basePath, dir.getPath()).isDirectory())
        throw new IllegalArgumentException("Not a directory: " + dir);
      zipDirectory(basePath, dir, out);
    }
    out.close();
  }

  private static void writeFile(File from, OutputStream out) throws IOException {
    FileInputStream in = new FileInputStream(from);
    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1)
      out.write(buffer, 0, bytesRead);
    in.close();
  }

  private static void zipDirectory(File basePath, File d, ZipOutputStream out) throws IOException {
    String[] entries = new File(basePath, d.getPath()).list();
    for (String entry : entries) {
      File f = new File(d, entry);
      File fullPath = new File(basePath, f.getPath());
      if (fullPath.isDirectory()) {
        zipDirectory(basePath, f, out);
      } else {
        ZipEntry zipEntry = new ZipEntry(f.getPath()); // Make a ZipEntry
        out.putNextEntry(zipEntry); // Store zipEntry
        writeFile(fullPath, out);
      }
    }
  }
}
